package com.rongchuang.util;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ConverterUtil {

    /**
     * 将源对象转换为目标对象
     *
     * @param source 源对象
     * @param targetClass 目标对象类
     * @param <S> 源类型
     * @param <T> 目标类型
     * @return 目标对象实例
     */
    public static <S, T> T convertTo(S source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        try {
            T target = targetClass.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
            return target;
        } catch (Exception e) {
            throw new RuntimeException("Conversion error", e);
        }
    }

    /**
     * 将源对象列表转换为目标对象列表
     *
     * @param sourceList 源对象列表
     * @param targetClass 目标对象类
     * @param <S> 源类型
     * @param <T> 目标类型
     * @return 目标对象实例列表
     */
    public static <S, T> List<T> convertToList(List<S> sourceList, Class<T> targetClass) {
        if (sourceList == null) {
            return null;
        }
        return sourceList.stream()
                .map(source -> convertTo(source, targetClass))
                .collect(Collectors.toList());
    }

    /**
     * 获取源对象中属性值为 null 的属性名数组
     *
     * @param source 源对象
     * @return 属性值为 null 的属性名数组
     */
    private static String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<>();
        for (java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }
}
